package com.rupeng.util;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

import javax.servlet.http.HttpSession;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * 短信验证码工具类
 */
public class SMSUtils {

    private static final Logger logger = LogManager.getLogger(SMSUtils.class);

    private static final String SESSION_KEY_SMS_CODE = "sessionKeySMSCode";//表示邮件验证码
    private static final String SESSION_KEY_SMS_PHONE = "sessionKeySMSPhone";//表示邮件收件人
    private static final String SESSION_KEY_SMS_TIME = "sessionKeySMSTime";//表示邮件发送时间
    private static final String SESSION_KEY_SMS_REMAIN_CHECK_COUNT = "sessionKeySMSRemainCheckCount";//表示剩余验证次数

    public static final int CHECK_RESULT_TRUE = 1;//表示验证成功
    public static final int CHECK_RESULT_FLASE = 2;//表示验证失败
    public static final int CHECK_RESULT_INVALID = 3;//表示验证码失效，需要重新发送

    public static int checkSMSCode(HttpSession session, String phone, String requestCode) {
        if (phone == null || requestCode == null) {
            logger.debug("检查短信验证码失败，phone{}，requestCode：{}", phone, requestCode);
            return CHECK_RESULT_FLASE;
        }
        String sessionPhone = (String) session.getAttribute(SESSION_KEY_SMS_PHONE);
        if (!phone.equals(sessionPhone)) {
            logger.debug("检查短信验证码失败，phone{}，requestCode：{}，sessionPhone：{}", phone, requestCode, sessionPhone);
            return CHECK_RESULT_FLASE;
        }
        Long sendTime = (Long) session.getAttribute(SESSION_KEY_SMS_TIME);
        //验证码过期失效
        if (sendTime - System.currentTimeMillis() > 1000 * 60 * 30) {
            logger.debug("检查短信验证码失败，验证码过期，phone：{}，requestCode：{}", phone, requestCode);
            return CHECK_RESULT_INVALID;
        }

        //如果验证码不匹配
        String sessionCode = (String) session.getAttribute(SESSION_KEY_SMS_CODE);
        Integer remainCount = (Integer) session.getAttribute(SESSION_KEY_SMS_REMAIN_CHECK_COUNT);

        if (!requestCode.equalsIgnoreCase(sessionCode)) {

            remainCount--;
            //没有剩余验证次数了
            if (remainCount <= 0) {
                session.removeAttribute(SESSION_KEY_SMS_CODE);
                session.removeAttribute(SESSION_KEY_SMS_REMAIN_CHECK_COUNT);
                session.removeAttribute(SESSION_KEY_SMS_TIME);
                session.removeAttribute(SESSION_KEY_SMS_PHONE);
                logger.debug("检查邮件验证码失败，验证码错误，phone：{}，requestCode：{}，sessionCode：{}，remainCount：{}", phone,
                        requestCode, sessionCode, remainCount);
                return CHECK_RESULT_INVALID;
            } else {
                session.setAttribute(SESSION_KEY_SMS_REMAIN_CHECK_COUNT, remainCount);
                logger.debug("检查邮件验证码失败，验证码错误，phone：{}，requestCode：{}，sessionCode：{}，remainCount：{}", phone,
                        requestCode, sessionCode, remainCount);
                return CHECK_RESULT_FLASE;
            }
        }

        //验证码匹配
        session.removeAttribute(SESSION_KEY_SMS_CODE);
        session.removeAttribute(SESSION_KEY_SMS_REMAIN_CHECK_COUNT);
        session.removeAttribute(SESSION_KEY_SMS_TIME);
        session.removeAttribute(SESSION_KEY_SMS_PHONE);

        logger.debug("检查邮件验证码成功，phone：{}，requestCode：{}，sessionCode：{}，remainCount：{}", phone, requestCode, sessionCode,
                remainCount);
        return CHECK_RESULT_TRUE;
    }

    public static void sendSMSCode(HttpSession session, String url, String appKey, String appSecret, String template,
            String phone) {
       
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);
        String nonce = new Random().nextInt(90000) + 10000 + "";
        String curTime = String.valueOf((new Date()).getTime() / 1000L);
        String checkSum = CheckSumBuilder.getCheckSum(appSecret, nonce, curTime);
        httpPost.addHeader("AppKey", appKey);
        httpPost.addHeader("Nonce", nonce);
        httpPost.addHeader("CurTime", curTime);
        httpPost.addHeader("CheckSum", checkSum);
        httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        
/*        StringBuilder builder = new StringBuilder();
        builder.append(url).append("?userName=").append(username);
        builder.append("&appKey=").append(appKey);
        builder.append("&templateId=").append(template);
        builder.append("&code=").append(smsCode);
        builder.append("&phoneNum=").append(phone);*/
        
        nvps.add(new BasicNameValuePair("templateid", template));
        nvps.add(new BasicNameValuePair("mobile", phone));
        nvps.add(new BasicNameValuePair("codeLen", "5"));
        String result = null;
        try {
            //String result = HttpUtils.get(builder.toString());
        	httpPost.setEntity(new UrlEncodedFormEntity(nvps, "utf-8"));
        	HttpResponse response = httpClient.execute(httpPost);
        	result = EntityUtils.toString(response.getEntity(), "utf-8");
        	SMSCodeResult smsResult = JsonUtils.toBean(result, SMSCodeResult.class);
        	System.out.println(smsResult.toString());
            if (smsResult.getCode() == 200) {
                session.setAttribute(SESSION_KEY_SMS_CODE, smsResult.getObj());
                session.setAttribute(SESSION_KEY_SMS_PHONE, phone);
                session.setAttribute(SESSION_KEY_SMS_TIME, System.currentTimeMillis());
                session.setAttribute(SESSION_KEY_SMS_REMAIN_CHECK_COUNT, 5);
                logger.debug("发送短信验证码成功，phone：{}，code：{}", phone, smsResult.getObj());
            } else {
                throw new RuntimeException("发送短信验证码失败，返回结果为：" + result);
            }
        } catch (Exception e) {
            logger.debug("发送短信验证码失败，phone：{}，msg：{}", phone, result, e);
            throw new RuntimeException("发送短信验证码失败", e);
        }
    }

    @SuppressWarnings("unused")
    private static class SMSCodeResult {
        private int code;
        private String msg;
        private String obj;
		public int getCode() {
			return code;
		}
		public void setCode(int code) {
			this.code = code;
		}
		public String getMsg() {
			return msg;
		}
		public void setMsg(String msg) {
			this.msg = msg;
		}
		public String getObj() {
			return obj;
		}
		public void setObj(String obj) {
			this.obj = obj;
		}
		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + code;
			result = prime * result + ((msg == null) ? 0 : msg.hashCode());
			result = prime * result + ((obj == null) ? 0 : obj.hashCode());
			return result;
		}
		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			SMSCodeResult other = (SMSCodeResult) obj;
			if (code != other.code)
				return false;
			if (msg == null) {
				if (other.msg != null)
					return false;
			} else if (!msg.equals(other.msg))
				return false;
			if (this.obj == null) {
				if (other.obj != null)
					return false;
			} else if (!this.obj.equals(other.obj))
				return false;
			return true;
		}
		@Override
		public String toString() {
			return "SMSCodeResult [code=" + code + ", msg=" + msg + ", obj=" + obj + "]";
		}
		
    }
}

//网易云信API
class CheckSumBuilder {
    // 计算并获取CheckSum
    public static String getCheckSum(String appSecret, String nonce, String curTime) {
        return encode("sha1", appSecret + nonce + curTime);
    }

    // 计算并获取md5值
    public static String getMD5(String requestBody) {
        return encode("md5", requestBody);
    }

    private static String encode(String algorithm, String value) {
        if (value == null) {
            return null;
        }
        try {
            MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
            messageDigest.update(value.getBytes());
            return getFormattedText(messageDigest.digest());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    private static String getFormattedText(byte[] bytes) {
        int len = bytes.length;
        StringBuilder buf = new StringBuilder(len * 2);
        for (int j = 0; j < len; j++) {
            buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
            buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
        }
        return buf.toString();
    }
    private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
}
